package com.erlang4j.internal.messages;

import static com.erlang4j.api.Erlang4jMessageLanguage.atom;
import static com.erlang4j.api.Erlang4jMessageLanguage.binding;
import static com.erlang4j.api.Erlang4jMessageLanguage.list;
import static com.erlang4j.api.Erlang4jMessageLanguage.string;
import static com.erlang4j.api.Erlang4jMessageLanguage.tuple;
import junit.framework.TestCase;

import com.ericsson.otp.erlang.OtpErlangObject;
import com.ericsson.otp.erlang.OtpErlangTuple;
import com.erlang4j.api.IBinding;

public class MessageParserTest extends TestCase {

	private final static MessageParser parser = new MessageParser();

	public void testSimple() {
		checkParser("X", atom("fred"), //
				"X", atom("fred"));
		checkParser("{mark,Value}", tuple(atom("mark"), string("value")), //
				"Value", string("value"));
		checkParser("[mark,Value]", list(atom("mark"), string("value")), //
				"Value", string("value"));
		checkParser("{a,b,[mark,{c,Value},d]}", //
				tuple(atom("a"), atom("b"), list(atom("mark"), tuple(atom("c"), string("value")), atom("d"))), //
				"Value", string("value"));
	}

	public void testWithExistingBindings() {
		IBinding initial = binding("X", string("xvalue"));
		checkParser(initial, "{mark,X,Y}", tuple(atom("mark"), string("xvalue"), string("yvalue")), //
				"X", string("xvalue"), "Y", string("yvalue"));
		checkParser(initial, "{mark,X,X}", tuple(atom("mark"), string("xvalue"), string("xvalue")), //
				"X", string("xvalue"));
		checkParser(initial, "[mark,X,X]", list(atom("mark"), string("xvalue"), string("xvalue")), //
				"X", string("xvalue"));
	}

	public void testWhenCannotBind() {
		checkParserInvalid("{mark,Value}", tuple(atom("notmark"), string("value")));

		IBinding initial = binding("X", string("xvalue"));
		checkParserInvalid(initial, "{mark,X}", tuple(atom("mark"), string("value")));

		checkParserInvalid("{a,b,[mark,{c,Value},e]}", //
				tuple(atom("a"), atom("b"), list(atom("mark"), tuple(atom("c"), string("value")), atom("d"))));
		checkParserInvalid("{a,b,[mark,{c,Value,d},d]}", //
				tuple(atom("a"), atom("b"), list(atom("mark"), tuple(atom("c"), string("value")), atom("d"))));
	}

	private void checkParserInvalid(String parse, OtpErlangTuple tuple) {
		checkParserInvalid(new Binding(), parse, tuple);
	}

	private void checkParserInvalid(IBinding initialBinding, String parse, OtpErlangTuple object) {
		IBinding actual = parser.parse(object, parse, initialBinding);
		assertFalse(actual.isValid());
		assertEquals(Binding.invalid, actual);
	}

	private void checkParser(String parse, OtpErlangObject object, Object... nameTypesAndValues) {
		checkParser(new Binding(), parse, object, nameTypesAndValues);
	}

	private void checkParser(IBinding initialBinding, String parse, OtpErlangObject object, Object... nameTypesAndValues) {
		IBinding expected = binding(nameTypesAndValues);
		IBinding actual = parser.parse(object, parse, initialBinding);
		assertTrue(actual.isValid());
		assertEquals(expected, actual);

	}

}
